﻿/*-
 * Copyright (c) 1982, 1986, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)protosw.h	8.1 (Berkeley) 6/2/93
 */

/*
 * Protocol switch table.
 *
 * Each protocol has a handle initializing one of these structures,
 * which is used for protocol-protocol and system-protocol communication.
 *
 * A protocol is called through the pr_init entry before any other.
 * Thereafter it is called every 200ms through the pr_fasttimo entry and
 * every 500ms through the pr_slowtimo for timer based actions.
 * The system will call the pr_drain entry if it is low on space and
 * this should throw away any non-critical data.
 *
 * Protocols pass data between themselves as chains of mbufs using
 * the pr_input and pr_output hooks.  Pr_input passes data up (towards
 * UNIX) and pr_output passes it down (towards the imps); control
 * information passes up and down on pr_ctlinput and pr_ctloutput.
 * The protocol is responsible for the space occupied by any the
 * arguments to these entries and must dispose it.
 *
 * The userreq routine interfaces protocols to the system and is
 * described below.
 */
/*
	下面eg.都是以icmp包举例
	{ SOCK_RAW, &inetdomain,	 IPPROTO_ICMP,	 PR_ATOMIC|PR_ADDR,  
	   icmp_input,	 rip_output, 0, 	 rip_ctloutput,
	   rip_usrreq,
	   0,		 0, 	 0, 	 0, 	 icmp_sysctl
	 }
*/
/* 某个协议的软件处理信息 */
struct protosw {
	short	pr_type;			/* 指示协议的通信语义，eg.SOCK_RAW，含义与socket结构的so_type字段相同 */
	struct	domain *pr_domain;	/* domain protocol a member of，该协议所处的域 */
	short	pr_protocol;		/* protocol number, 在某个域中协议的编号，eg.IPPROTO_ICMP */
	short	pr_flags;			/* 标识协议的附加特性，eg.PR_ATOMIC */
	
	/* protocol-protocol hooks */
	void	(*pr_input)();		/* 处理从一个低层协议输入的数据，eg.icmp_input */
	int		(*pr_output)();		/* 处理从一个高层协议输出的数据，eg.rip_output */
	void	(*pr_ctlinput)();	/* 处理来自下层的控制信息 例如.icmp错误*/
	int		(*pr_ctloutput)();	/* 处理来自上层的控制信息, eg.rip_ctloutput */
	
	/* user-protocol hook */
	int		(*pr_usrreq)();		/* 处理来自进程的所有通信请求, eg.rip_usrreq、tcp_usrreq */
	
	/* utility hooks */
	void	(*pr_init)();		/* initialization hook */
	void	(*pr_fasttimo)();	/* fast timeout (200ms)，周期性协议函数 */
	void	(*pr_slowtimo)();	/* slow timeout (500ms)，周期性协议函数 */
	void	(*pr_drain)();		/* flush any excess space possible，在内存缺乏时被 m_reclaim调用，它请求协议释放尽可能多的内存。 */
	int		(*pr_sysctl)();		/* sysctl for protocol，为sysctl命令提供一个接口，一种修改系统范围的参数的方式，如允许转发分组或UDP检验和计算。*/
};

#define	PR_SLOWHZ	2		/* 2 slow timeouts per second */
#define	PR_FASTHZ	5		/* 5 fast timeouts per second */

/*
 * Values for pr_flags.
 如果一个协议支持 PR_ADDR，必须也支持 PR_ATOMIC。PR_ADDR和PR_CONNREQUIRED是互斥的。
 当设置了PR_WANTRCVD，并当插口层将插口接收缓存中的数据传递给一个进程时(即当在接收缓存中有更多空间可用时 )，它通知协议层。
 PR_WANTRCVD 指示访问权限控制报文能通过连接来传递。
 PR_RIGHTS 访问权限要求内核中的其他支持来确保在接收进程没有销毁报文时能完成正确的清除工作。仅 Unix域支持访问权限，用来在进程间传递描述符。
 */
#define	PR_ATOMIC			0x01		/* 每个进程请求映射为一个单个的协议请求 */
#define	PR_ADDR				0x02		/* 协议在每个数据报中都传递地址 */
#define	PR_CONNREQUIRED		0x04		/* connection required by protocol */
#define	PR_WANTRCVD			0x08		/* want PRU_RCVD calls, 当一个进程接收到数据时通知协议 */
#define	PR_RIGHTS			0x10		/* 协议支持访问权限 */

/*
 * The arguments to usrreq are:
 *	(*protosw[].pr_usrreq)(up, req, m, nam, opt);
 * where up is a (struct socket *), req is one of these requests,
 * m is a optional mbuf chain containing a message,
 * nam is an optional mbuf chain containing an address,
 * and opt is a pointer to a socketopt structure or nil.
 * The protocol is responsible for disposal of the mbuf chain m,
 * the caller is responsible for any space held by nam and opt.
 * A non-zero return from usrreq gives an
 * UNIX error number which should be passed to higher level software.
 */
#define	PRU_ATTACH		0	/* 创建socket时，使用 */
#define	PRU_DETACH		1	/* 关闭socket时，使用 */
#define	PRU_BIND		2	/* 把地址绑定到socket时，使用 */
#define	PRU_LISTEN		3	/* 开始监听连接请求时，使用 */
#define	PRU_CONNECT	4	/* 已经与对端建立连接时，使用 */
#define	PRU_ACCEPT		5	/* 接受对端连接时，使用 */
#define	PRU_DISCONNECT	6	/* 与对端断开连接时，使用。通常发生在关闭socket时 */
#define	PRU_SHUTDOWN	7	/* 不再主动与对端通信时，使用 */
#define	PRU_RCVD		8	/* 进程已经收到一些数据，现在有更多空间接受数据时，使用 */
#define	PRU_SEND		9	/* 发送正常数据时，使用 */
#define	PRU_ABORT		10	/* 异常终止连接时，使用。快速 DISCONNECT/DETATCH */
#define	PRU_CONTROL	11	/* control operations on protocol */
#define	PRU_SENSE		12	/* return status into m */
#define	PRU_RCVOOB		13	/* retrieve out of band data */
#define	PRU_SENDOOB	14	/* 发送OOB数据时，使用 */
#define	PRU_SOCKADDR	15	/* 获取socket本地地址时，使用 */
#define	PRU_PEERADDR	16	/* 获取socket对端地址时，使用 */
#define	PRU_CONNECT2	17	/* 只用于Unix域，创建2个socket并将它们连接起来，Unix管道就是用这种方式实现的 */
/* begin for protocols internal use */
#define	PRU_FASTTIMO		18	/* 200ms timeout */
#define	PRU_SLOWTIMO		19	/* 500ms timeout */
#define	PRU_PROTORCV		20	/* receive from below */
#define	PRU_PROTOSEND		21	/* send to below */

#define	PRU_NREQ		21

#ifdef PRUREQUESTS
char *prurequests[] = {
	"ATTACH",	"DETACH",	"BIND",		"LISTEN",
	"CONNECT",	"ACCEPT",	"DISCONNECT",	"SHUTDOWN",
	"RCVD",		"SEND",		"ABORT",	"CONTROL",
	"SENSE",	"RCVOOB",	"SENDOOB",	"SOCKADDR",
	"PEERADDR",	"CONNECT2",	"FASTTIMO",	"SLOWTIMO",
	"PROTORCV",	"PROTOSEND",
};
#endif

/*
 * The arguments to the ctlinput routine are
 *	(*protosw[].pr_ctlinput)(cmd, sa, arg);
 * where cmd is one of the commands below, sa is a pointer to a sockaddr,
 * and arg is an optional caddr_t argument used within a protocol family.
 */
#define	PRC_IFDOWN		0	/* interface transition */
#define	PRC_ROUTEDEAD		1	/* select new route if possible ??? */
#define	PRC_QUENCH2		3	/* DEC congestion bit says slow down */
#define	PRC_QUENCH		4	/* some one said to slow down */
#define	PRC_MSGSIZE		5	/* message size forced drop */
#define	PRC_HOSTDEAD		6	/* host appears to be down */
#define	PRC_HOSTUNREACH		7	/* deprecated (use PRC_UNREACH_HOST) */
#define	PRC_UNREACH_NET		8	/* no route to network */
#define	PRC_UNREACH_HOST	9	/* no route to host */
#define	PRC_UNREACH_PROTOCOL	10	/* dst says bad protocol */
#define	PRC_UNREACH_PORT	11	/* bad port # */
/* was	PRC_UNREACH_NEEDFRAG	12	   (use PRC_MSGSIZE) */
#define	PRC_UNREACH_SRCFAIL	13	/* source route failed */
#define	PRC_REDIRECT_NET	14	/* net routing redirect */
#define	PRC_REDIRECT_HOST	15	/* host routing redirect */
#define	PRC_REDIRECT_TOSNET	16	/* redirect for type of service & net */
#define	PRC_REDIRECT_TOSHOST	17	/* redirect for tos & host */
#define	PRC_TIMXCEED_INTRANS	18	/* packet lifetime expired in transit */
#define	PRC_TIMXCEED_REASS	19	/* lifetime expired on reass q */
#define	PRC_PARAMPROB		20	/* header incorrect */

#define	PRC_NCMDS		21

#define	PRC_IS_REDIRECT(cmd)	\
	((cmd) >= PRC_REDIRECT_NET && (cmd) <= PRC_REDIRECT_TOSHOST)

#ifdef PRCREQUESTS
char	*prcrequests[] = {
	"IFDOWN", "ROUTEDEAD", "#2", "DEC-BIT-QUENCH2",
	"QUENCH", "MSGSIZE", "HOSTDEAD", "#7",
	"NET-UNREACH", "HOST-UNREACH", "PROTO-UNREACH", "PORT-UNREACH",
	"#12", "SRCFAIL-UNREACH", "NET-REDIRECT", "HOST-REDIRECT",
	"TOSNET-REDIRECT", "TOSHOST-REDIRECT", "TX-INTRANS", "TX-REASS",
	"PARAMPROB"
};
#endif

/*
 * The arguments to ctloutput are:
 *	(*protosw[].pr_ctloutput)(req, so, level, optname, optval);
 * req is one of the actions listed below, so is a (struct socket *),
 * level is an indication of which protocol layer the option is intended.
 * optname is a protocol dependent socket option request,
 * optval is a pointer to a mbuf-chain pointer, for value-return results.
 * The protocol is responsible for disposal of the mbuf chain *optval
 * if supplied,
 * the caller is responsible for any space held by *optval, when returned.
 * A non-zero return from usrreq gives an
 * UNIX error number which should be passed to higher level software.
 */
#define	PRCO_GETOPT	0
#define	PRCO_SETOPT	1

#define	PRCO_NCMDS	2

#ifdef PRCOREQUESTS
char	*prcorequests[] = {
	"GETOPT", "SETOPT",
};
#endif

#ifdef KERNEL
extern	struct protosw *pffindproto(), *pffindtype();
#endif
